import test from 'ava'
import ceno from '../src'
import { createHttpTestServer } from './helpers/create-http-test-server' 
import { expectTypeOf } from 'expect-type'

const httpMethods = ['get', 'post', 'put', 'delete', 'patch', 'head'] as const
for (const method of httpMethods) {
    test(`${method.toUpperCase()} 请求正常工作`, async (t) => {
        method === 'head' ? t.plan(2) : t.plan(1)

        const server = await createHttpTestServer()

        server[method]('/', (request, response) => {
            if (method === 'head') {
                response.end(request.method)
                t.pass()
            } else {
                response.end(request.method)
            }
        })

        const response = await ceno[method](server.url).text()

        t.is(response, method === 'head' ? '' : method.toUpperCase())

        await server.close()
    })
}

test('POST 请求发送 JSON 数据', async (t) => {
    t.plan(2)
  
    const server = await createHttpTestServer()
    server.post('/', (request, response) => {
      t.is(request.headers['content-type'], 'application/json')
      response.json(request.body)
    })
  
    const json = { cake: 'cake' }
  
    const data = await ceno.post(server.url, { json }).json()
  
    t.deepEqual(data, json)
  
    await server.close()
})

test('不能在 GET 或 HEAD 请求中使用 `body` 选项', async (t) => {
    t.throws(
      () => {
        void ceno.get('https://example.com', { body: 'body'})
      },
      {
        message: 'Request with GET/HEAD method cannot have body.'
      }
    )
  
    t.throws(
      () => {
        void ceno.head('https://example.com', { body: 'body'})
      },
      {
        message: 'Request with GET/HEAD method cannot have body.'
      }
    )
})
  
test('不能在 GET 或 HEAD 请求中使用 `json` 选项', async (t) => {
    t.throws(
      () => {
        void ceno.get('https://example.com', { json: 'json'})
      },
      {
        message: 'Request with GET/HEAD method cannot have body.'
      }
    )
  
    t.throws(
      () => {
        void ceno.head('https://example.com', { json: 'json'})
      },
      {
        message: 'Request with GET/HEAD method cannot have body.'
      }
    )
})
  
test('`json` 选项会覆盖 `body` 选项', async (t) => {
    t.plan(2)
  
    const server = await createHttpTestServer()
    server.post('/', (request, response) => {
      t.is(request.headers['content-type'], 'application/json')
      response.json(request.body)
    })
  
    const json = { cake: 'cake' }
  
    const response = await ceno.post(server.url, 
      { json, body: 'body' }
    ).json()
  
    t.deepEqual(response, json)
  
    await server.close()
})
  
test('自定义 Headers', async (t) => {
    const server = await createHttpTestServer()
    server.get('/', (request, response) => {
      response.end(request.headers['cake'])
    })
  
    const response = await ceno.get(server.url, { headers: { cake: 'cake' } }).text()
  
    t.is(
      response,
      'cake'
    )
  
    await server.close()
})
  
test('带自定义 Headers 实例的 JSON 请求', async (t) => {
    t.plan(3)
  
    const server = await createHttpTestServer()
    server.post('/', (request, response) => {
      t.is(request.headers['cake'], 'cake')
      t.is(request.headers['content-type'], 'application/json')
      response.json(request.body)
    })
  
    const json = { cake: 'cake' }
  
    const response = await ceno.post(server.url, { headers: { cake: 'cake' }, json }).json()
  
    t.deepEqual(response, json)
  
    await server.close()
})
  
test('使用自定义 accept Headers 的 `.json()`', async (t) => {
    t.plan(2)
  
    const server = await createHttpTestServer()
    server.get('/', (request, response) => {
      t.is(request.headers['accept'], 'eat/cake')
      response.json({})
    })
  
    const response = await ceno.get(server.url,{
      headers: { accept: 'eat/cake' }
    }).json()
  
    t.deepEqual(response, {})
  
    await server.close()
})
  
test('当响应为分块传输时的 `.json()`', async (t) => {
    const server = await createHttpTestServer()
    server.get('/', (request, response) => {
      response.write('[')
      response.write('"one"')
      response.write(',')
      response.write('"two"')
      response.end(']')
    })
  
    const response = await ceno.get<['one', 'two']>(server.url).json()
  
    expectTypeOf(response).toEqualTypeOf<['one', 'two']>()
  
    t.deepEqual(response, ['one', 'two'])
  
    await server.close()
})
  
test('当使用无效 JSON 主体时的 `.json()`', async (t) => {
    const server = await createHttpTestServer()
    server.get('/', (request, response) => {
      t.is(request.headers['accept'], 'application/json')
      response.end('invalid json')
    })
  
    await t.throwsAsync(
      ceno.get(server.url).json(),
      {
        message: 'Unexpected token \'i\', "invalid json" is not valid JSON'
      }
    )
  
    await server.close()
})
  
test('当请求体为空时的 `.json()`', async (t) => {
    const server = await createHttpTestServer()
    server.get('/', (request, response) => {
      t.is(request.headers['accept'], 'application/json')
      response.end()
    })
  
    const response = await ceno.get(server.url).json()
  
    t.deepEqual(response, '')
  
    await server.close()
})

test('`.text()` 返回响应的文本内容', async (t) => {
    const server = await createHttpTestServer()

    server.get('/', (request, response) => {
        response.end('Hello Ceno')
    })

    const response = await ceno.get(server.url).text()

    t.is(response, 'Hello Ceno')

    await server.close()
})